package dao

import (
	"advertising/internal/dal"
	"advertising/internal/define"
	"advertising/internal/models"
	"context"
	"strings"
	"time"

	"192.168.1.75/go-pkg/helper"
	"github.com/samber/lo"
	"gorm.io/gen/field"
	"gorm.io/gorm"
)

type PublishScheduleDevice struct{}

// 投放计划设备创建
func (PublishScheduleDevice) Create(ctx context.Context, db *gorm.DB, merchantID, ScheduleID, RobotName string, startTime, endTime int64, terminalType int) (err error) {
	m := dal.Use(db).PublishScheduleDevice
	tx := m.WithContext(ctx)
	var d models.PublishScheduleDevice
	d.ID, _ = helper.UUID{}.String()
	d.MerchantID = merchantID
	d.ScheduleID = ScheduleID
	d.RobotName = RobotName
	d.StartTime = startTime
	d.EndTime = endTime
	d.PublishType = 1             // 新增
	d.TerminalType = terminalType // 1 - 前屏 97, 2 - 后屏 98
	d.CreatedAt = time.Now().Unix()
	tx.Create(&d)
	return
}

// 投放计划关联的设备列表
// withoutDelete 不包含待删除，true 不包含 ，false 包含
func (PublishScheduleDevice) List(ctx context.Context, db *gorm.DB, merchantID, scheduleID, robotName string, terminalType int, startTime, endTime int64, withoutDelete bool, page, limit int) (res []*models.PublishScheduleDevice, count int64, err error) {
	m := dal.Use(db).PublishScheduleDevice
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if withoutDelete {
		tx = tx.Where(m.PublishType.Neq(3)) // 不包含待删除
	}
	tx = tx.Where(m.PublishStatus.Neq(define.ORDER_FAILED)) // 不包含待删除

	if merchantID != "" && merchantID != "1" {
		if strings.Contains(merchantID, ",") {
			tx = tx.Where(m.MerchantID.In(strings.Split(merchantID, ",")...))
		} else {
			tx = tx.Where(m.MerchantID.Eq(merchantID))
		}
	}
	if scheduleID != "" {
		if strings.Contains(scheduleID, ",") {
			tx = tx.Where(m.ScheduleID.In(strings.Split(scheduleID, ",")...))
		} else {
			tx = tx.Where(m.ScheduleID.Eq(scheduleID))
		}
	}
	if robotName != "" {
		if strings.Contains(robotName, ",") {
			tx = tx.Where(m.RobotName.In(strings.Split(robotName, ",")...))
		} else {
			tx = tx.Where(m.RobotName.Eq(robotName))
		}
	}
	if terminalType != 0 {
		tx = tx.Where(m.TerminalType.Eq(terminalType))
	}
	if startTime != 0 {
		tx = tx.Where(m.StartTime.Gte(startTime))
	}
	if endTime != 0 {
		tx = tx.Where(m.EndTime.Lte(endTime))
	}
	list, count, _ := tx.Order(m.ID.Desc()).FindByPage(Offset(page, limit))
	return list, count, nil
}

// 待删除，投放完成后删除
func (PublishScheduleDevice) SetToDelete(ctx context.Context, db *gorm.DB, scheduleID, robotName string, terminalType int) (err error) {
	m := dal.Use(db).PublishScheduleDevice
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if scheduleID != "" {
		tx = tx.Where(m.ScheduleID.Eq(scheduleID))
	}
	if robotName != "" {
		if strings.Contains(robotName, ",") {
			tx = tx.Where(m.RobotName.In(strings.Split(robotName, ",")...))
		} else {
			tx = tx.Where(m.RobotName.Eq(robotName))
		}
	}
	if terminalType != 0 {
		tx = tx.Where(m.TerminalType.Eq(terminalType))
	}
	tx.UpdateSimple(
		m.PublishType.Value(3), // 类型为3 删除
		m.PublishTime.Value(0), // 发布时间置为0
	)
	return nil
}

// 删除
func (PublishScheduleDevice) Delete(ctx context.Context, db *gorm.DB, ID, scheduleID, robotName string, terminalType int) (err error) {
	m := dal.Use(db).PublishScheduleDevice
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if ID != "" {
		tx = tx.Where(m.ID.Eq(ID))
	}
	if scheduleID != "" {
		tx = tx.Where(m.ScheduleID.Eq(scheduleID))
	}
	if robotName != "" {
		if strings.Contains(robotName, ",") {
			tx = tx.Where(m.RobotName.In(strings.Split(robotName, ",")...))
		} else {
			tx = tx.Where(m.RobotName.Eq(robotName))
		}
	}
	if terminalType != 0 {
		tx = tx.Where(m.TerminalType.Eq(terminalType))
	}
	tx.Updates(m.DeletedAt.Value(time.Now().Unix()))
	return nil
}

// 投放计划设备数
func (PublishScheduleDevice) ScheduleRobotCount(ctx context.Context, db *gorm.DB, scheduleID string) (res []struct {
	ScheduleID  string `gorm:"column:schedule_id"`
	DeviceCount int64  `gorm:"column:device_count"`
}) {
	m := dal.Use(db).PublishScheduleDevice
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0)).
		Where(m.PublishType.Neq(3))
	if scheduleID != "" {
		if strings.Contains(scheduleID, ",") {
			tx = tx.Where(m.ScheduleID.In(strings.Split(scheduleID, ",")...))
		} else {
			tx = tx.Where(m.ScheduleID.Eq(scheduleID))
		}
	}
	tx.Select(m.ScheduleID, m.ID.Count().As("device_count")).
		Group(m.ScheduleID, m.RobotName).
		Scan(&res)
	return
}

// 更新投放时间
func (PublishScheduleDevice) UpdatePublishTime(ctx context.Context, db *gorm.DB, scheduleID, robotName string, terminalType int, currentStatus, publishStatus int, publishTime int64) (err error) {
	m := dal.Use(db).PublishScheduleDevice
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if scheduleID != "" {
		if strings.Contains(scheduleID, ",") {
			tx = tx.Where(m.ScheduleID.In(strings.Split(scheduleID, ",")...))
		} else {
			tx = tx.Where(m.ScheduleID.Eq(scheduleID))
		}
	}
	if robotName != "" {
		if strings.Contains(robotName, ",") {
			tx = tx.Where(m.RobotName.In(strings.Split(robotName, ",")...))
		} else {
			tx = tx.Where(m.RobotName.Eq(robotName))
		}
	}
	if terminalType != 0 {
		tx = tx.Where(m.TerminalType.Eq(terminalType))
	}
	if currentStatus != 0 {
		tx = tx.Where(m.PublishStatus.Eq(currentStatus))
	}
	tx.UpdateSimple(
		m.PublishStatus.Value(publishStatus),
		m.PublishTime.Value(publishTime),
	)
	return
}

// 获取推送设备列表
func (PublishScheduleDevice) GetPublishDeviceList(ctx context.Context, db *gorm.DB, devices string) (deviceList []*models.PublishScheduleDevice) {
	device := dal.Use(db).PublishScheduleDevice
	schedule := dal.Use(db).PublishSchedule
	tx := device.WithContext(ctx).
		LeftJoin(schedule, schedule.ID.EqCol(device.ScheduleID)).
		Where(device.DeletedAt.Eq(0)).
		Where(schedule.DeletedAt.Eq(0))

	if devices != "" { // 强制推送时指定设备
		InValues := [][]interface{}{}
		for _, item := range strings.Split(devices, ",") { // 逗号分隔多个设备
			if item == "" {
				continue
			}
			d := strings.Split(item, "_") // '_'分隔设备和终端类型
			InValues = append(InValues, []interface{}{d[0], d[1]})
		}
		if len(InValues) > 0 {
			tx = tx.Where(device.WithContext(ctx).Columns(device.RobotName, device.TerminalType).In(field.Values(InValues)))
		}
	} else { // 常规推送限制时间
		// 投放中【1】意味着没有收到反馈，尝试再次发送
		tx = tx.Where(device.PublishStatus.Eq(1)).
			Where(schedule.Status.Eq(3)). // 投放计划属于投放中状态
			Limit(10)                     // 未指定设备时限制10个设备
	}

	deviceList, _ = tx.Group(device.RobotName, device.TerminalType).
		Order(device.PublishTime). // 投放时间正序
		Select(device.RobotName, device.TerminalType).
		Find()
	return
}

// 获取设备投放中的计划列表
func (PublishScheduleDevice) GetDeivcePublishScheduleList(ctx context.Context, db *gorm.DB, robotName string, terminalType int) (data []*models.PublishSchedule, err error) {
	if robotName == "" || terminalType == 0 {
		return
	}
	device := dal.Use(db).PublishScheduleDevice
	schedule := dal.Use(db).PublishSchedule
	list, err := schedule.WithContext(ctx).
		Join(device, schedule.ID.EqCol(device.ScheduleID)).
		Where(device.DeletedAt.Eq(0), device.RobotName.Eq(robotName), device.TerminalType.Eq(terminalType)).
		Where(device.PublishType.Neq(3)).                       // 剔除待删除设备
		Where(schedule.DeletedAt.Eq(0), schedule.Status.Eq(3)). // 投放中
		Select(schedule.ALL).
		Find()
	return list, err
}

type RobotScheduleWithMaterial struct {
	ScheduleID         string `json:"schedule_id"`          // 计划id
	ScheduleName       string `json:"schedule_name"`        // 计划名称
	MaterialID         string `json:"material_id"`          // 素材id
	MaterialName       string `json:"material_name"`        // 素材名称
	MaterialFile       string `json:"material_file"`        // 素材路径
	MaterialType       int32  `json:"material_type"`        // 素材类型
	StartTime          int32  `json:"start_time"`           // 开始时间
	EndTime            int32  `json:"end_time"`             // 结束时间
	Duration           int32  `json:"duration"`             // 素材时长
	RepeatTimes        int32  `json:"repeat_times"`         // 播放频次 【弃用】
	Orientation        int32  `json:"orientation"`          // 投放定向
	CreateUser         string `json:"create_user"`          // 投放账户id
	CreateUsername     string `json:"create_username"`      // 投放账户名称
	Gender             string `json:"gender"`               // 性别
	Age                string `json:"age"`                  // 年龄
	Tag                string `json:"tag"`                  // 标签
	Sort               int32  `json:"sort"`                 // 排序
	PublishType        int32  `json:"publish_type"`         // 投放类型
	Status             int32  `json:"status"`               // 状态
	ScheduleMaterialId string `json:"schedule_material_id"` // 计划素材id
}

// 获取设备投放中的计划列表带素材
func (PublishScheduleDevice) GetDeivcePublishScheduleMaterialList(ctx context.Context, db *gorm.DB, robotName string, terminalType int) (data []RobotScheduleWithMaterial, err error) {
	scheduleList, _ := PublishScheduleDevice{}.GetDeivcePublishScheduleList(ctx, db, robotName, terminalType)
	scheduleIDList := []string{}
	scheduleInfoMap := make(map[string]models.PublishSchedule)
	for _, v := range scheduleList {
		if !lo.Contains(scheduleIDList, v.ID) {
			scheduleIDList = append(scheduleIDList, v.ID)
		}
		scheduleInfoMap[v.ID] = *v
	}
	MaterialList, _ := PublishScheduleMaterial{}.MaterialList(ctx, db, strings.Join(scheduleIDList, ","))
	for _, v := range MaterialList {
		var item RobotScheduleWithMaterial
		item.ScheduleID = v.ScheduleID
		item.MaterialID = v.MaterialID
		item.MaterialName = v.Name
		item.MaterialFile = v.FilePath
		item.MaterialType = int32(v.Type)
		item.Sort = int32(v.Sort)
		if _, ok := scheduleInfoMap[v.ScheduleID]; ok {
			item.ScheduleName = scheduleInfoMap[v.ScheduleID].Name
			item.StartTime = int32(scheduleInfoMap[v.ScheduleID].StartTime)
			item.EndTime = int32(scheduleInfoMap[v.ScheduleID].EndTime)
			item.Duration = int32(v.Duration)
			item.CreateUser = scheduleInfoMap[v.ScheduleID].CreateUser
			item.CreateUsername = scheduleInfoMap[v.ScheduleID].CreateUserName
			item.Gender = scheduleInfoMap[v.ScheduleID].Gender
			item.Age = scheduleInfoMap[v.ScheduleID].Age
			item.Tag = scheduleInfoMap[v.ScheduleID].Tag
			item.PublishType = int32(scheduleInfoMap[v.ScheduleID].PublishType)
			item.Status = int32(scheduleInfoMap[v.ScheduleID].Status)
			if scheduleInfoMap[v.ScheduleID].PublishType == 1 { // 刊例
				item.Orientation = 0 // "-"
			} else if len(strings.Split(item.Gender, ",")) == len(define.GenderMap) && len(strings.Split(item.Age, ",")) == len(define.AgeMap) && len(strings.Split(item.Tag, ",")) == len(define.TagMap) {
				item.Orientation = 1 // 默认
			} else {
				item.Orientation = 2 // 定向
			}
		}
		data = append(data, item)
	}
	return data, nil
}
